home *** CD-ROM | disk | FTP | other *** search
/ CyberMycha 2005 May / CyberMycha 05-2005 (Poland).bin / Immortal / cotndemo.exe / Data1.cab / water_shaders.fx < prev    next >
Encoding:
Text File  |  2004-11-16  |  18.7 KB  |  534 lines

  1. // Adapted from NVidia's ocean.fx example.
  2. // Applied to the Nile, ponds, etc.
  3. // Also adapted from "Effective Water Simulation from Physical Models" in GPU Gems
  4. string description = "Water with Environment Map, Waves and Bump Map";
  5.  
  6. // Note that these matrices & the Time value must be "manually" 
  7. // loaded by C++ game code, but are automatically set within NVidia's FX Composer.
  8. float4x4 worldViewProj : WorldViewProjection;
  9. float4x4 worldMatrix   : World;
  10. float4x4 worldInverseTranspose : WorldInverseTranspose;
  11. float4x4 viewInverse : ViewInverse;
  12. float4x4 view : View;
  13.  
  14. // Time.  Used to animate waves, bump map.
  15. float time : Time < string UIWidget = "none"; >;
  16. //------------------------------------
  17.  
  18. // Bump map
  19. texture normalMap : Normal
  20. <
  21.     string ResourceName = "waves2.dds";
  22.     string TextureType = "2D";
  23. >;
  24.  
  25. // Cube map
  26. texture cubeMap : Environment
  27. <
  28.     string ResourceName = "CloudyHillsCubemap2.dds";
  29.     string TextureType = "Cube";
  30. >;
  31.  
  32. // Texture sampling attributes
  33. sampler2D normalMapSampler = sampler_state
  34. {
  35.     Texture = <normalMap>;
  36. #if 0
  37.     // this is a trick from Halo - use point sampling for sparkles
  38.     MagFilter = Linear;    
  39.     MinFilter = Point;
  40.     MipFilter = None;
  41. #else
  42.     MagFilter = Linear;    
  43.     MinFilter = Linear;
  44.     MipFilter = Linear;
  45.     AddressU = Wrap; // very important, otherwise the bump map disappears at certain orientations
  46.     AddressV = Wrap;
  47. #endif
  48. };
  49.  
  50. samplerCUBE envMapSampler = sampler_state
  51. {
  52.     Texture = <cubeMap>;
  53.     MinFilter = Linear;
  54.     MagFilter = Linear;
  55.     MipFilter = Linear;
  56. };
  57.  
  58. // NOTE: It may be worthwhile to set variables like bumpHeight to static const,
  59. // once we're done adjusting them.  I think this allows increased performance, but
  60. // that should be double-checked.  This means the values won't be visible to FX Composer.
  61.  
  62. float timeMod < string UIWidget = "none"; > = 200.0;
  63.  
  64. // "Height" of the bumps on the bump map
  65. float bumpHeight
  66. <
  67.     string UIWidget = "slider";
  68.     float UIMin = 0.0; float UIMax = 2.0; float UIStep = 0.01;
  69.     string UIName = "Bump Height";
  70. > = 0.3; // was 0.1
  71.  
  72. // Scale of bump map
  73. float2 textureScale
  74. <
  75.     string UIName = "Texture scale";
  76. > = { 1.0, 0.5 }; // was 8.0, 4.0
  77.  
  78. // How fast the bump map moves over the water.  Adds to current effect.
  79. float2 bumpSpeed
  80. <
  81.     string UIName = "Bumpmap translation speed";
  82. > = { 0.0, -0.05 }; // was -0.05, 0.0
  83.  
  84. // Exponent for calculating Fresnel reflectance.  Could probably be reduced and still look OK.
  85. float fresnelPower
  86. <
  87.     string UIName = "Fresnel exponent";
  88.     string UIWidget = "slider";
  89.     float UIMin = 1.0; float UIMax = 10.0; float UIStep = 0.01;
  90. > = 4.0; // was 4.0
  91.  
  92. // High dynamic range multiplier.  Increasing this will "blow out" (brighten) the bright spots on the water
  93. float hdrMultiplier
  94. <
  95.     string UIName = "HDR multiplier";
  96.     string UIWidget = "slider";
  97.     float UIMin = 0.0; float UIMax = 100.0; float UIStep = 0.01;
  98. > = 3.0; // was 3.0, make this 0.4?
  99.  
  100. // Position of the camera in world coordinates
  101. float3 eyePositionW : Direction
  102. <
  103.     string UIWidget = "Eye Position";
  104.     string Space = "material";
  105. > = {0.0f, 1.0f, 0.0f};
  106.  
  107. // Fog attribute
  108. float fogEnd
  109. <
  110.     string UIWidget = "slider";
  111.     float UIMin = 1.0;
  112.     float UIMax = 128.0;
  113.     float UIStep = 1.0;
  114.     string UIName = "fog end";
  115. > = 44.0;
  116.  
  117. // Calculated by C++: 1 / (FogEnd - FogStart)
  118. float fogEndMinusStartInv
  119. <
  120.     string UIWidget = "slider";
  121.     float UIMin = 0.01; 
  122.     float UIMax = 10.0;
  123.     float UIStep = 0.01;
  124.     string UIName = "fog end minus start inverse";
  125. > = 0.125;
  126.  
  127. // Deep water color.  This color will dominate when the camera is looking
  128. // straight down at the water (i.e. the eye vector is perpendicular to the water normal).
  129. float4 deepColor : Diffuse
  130. <
  131.     string UIName = "Deep water color";
  132. > = {0.0f, 0.0f, 0.1f, 1.0f};
  133.  
  134. // Shallow water color.  This color will dominate when the camera is looking
  135. // at a grazing angle to the water (i.e. the eye vector is close to parallel to the water normal).
  136. float4 shallowColor : Diffuse
  137. <
  138.     string UIName = "Shallow water color";
  139. > = {0.0, 0.5, 0.5, 1.0};
  140.  
  141. // Affects the color of the env. map reflection and other reflection attributes.
  142. float4 reflectionColor : Specular
  143. <
  144.     string UIName = "Reflection color";
  145. > = {1.0f, 1.0f, 1.0f, 1.0f};
  146.  
  147. // these are redundant, but makes the ui easier:
  148. float reflectionAmount
  149. <
  150.     string UIName = "Reflection amount";
  151.     string UIWidget = "slider";    
  152.     float UIMin = 0.0; float UIMax = 2.0; float UIStep = 0.01;    
  153. > = 1.0f; // was 1.0f
  154.  
  155. // Height of the waves.
  156. float waveAmp
  157. <
  158.     string UIName = "Wave amplitude";
  159.     string UIWidget = "slider";
  160.     float UIMin = 0.0; float UIMax = 10.0; float UIStep = 0.1;
  161. > = 0.005; // was 0.01
  162.  
  163. // Frequency of the waves.
  164. float waveFreq
  165. <
  166.     string UIName = "Wave frequency";
  167.     string UIWidget = "slider";
  168.     float UIMin = 0.0; float UIMax = 1.0; float UIStep = 0.001;
  169. > = 1.0; //was 0.1
  170. // wave functions
  171.  
  172. // Wave structure
  173. struct WAVE {
  174.   float freq;  // 2*PI / wavelength
  175.   float amp;   // amplitude
  176.   float phase; // speed * 2*PI / wavelength
  177.   float2 dir;  // direction
  178. };
  179.  
  180. // We'll mix a couple of waves with different heights, frequencies, etc.
  181. #define NWAVES 2
  182. WAVE wave[NWAVES] = {
  183.     { 1.0, 1.0, 0.5, float2(1, 0) },
  184.     { 2.0, 0.5, 1.3, float2(0.7, -0.7) }    
  185. };
  186.  
  187. // Determine the height of the wave at a given location and time
  188. float evaluateWave(WAVE w, float2 pos, float t)
  189. {
  190.   return w.amp * sin( dot(w.dir, pos)*w.freq + t*w.phase);
  191. }
  192. // derivative of wave function
  193. float evaluateWaveDeriv(WAVE w, float2 pos, float t)
  194. {
  195.   return w.freq*w.amp * cos( dot(w.dir, pos)*w.freq + t*w.phase);
  196. }
  197.  
  198. // sharp wave functions.  Makes waves with sharper peaks.
  199. float evaluateWaveSharp(WAVE w, float2 pos, float t, float k)
  200. {
  201.   return w.amp * pow(sin( dot(w.dir, pos)*w.freq + t*w.phase)* 0.5 + 0.5 , k);
  202. }
  203.  
  204. float evaluateWaveDerivSharp(WAVE w, float2 pos, float t, float k)
  205. {
  206.   return k*w.freq*w.amp * pow(sin( dot(w.dir, pos)*w.freq + t*w.phase)* 0.5 + 0.5 , k - 1) * cos( dot(w.dir, pos)*w.freq + t*w.phase);
  207. }
  208.  
  209. //------------------------------------
  210. // Passed in to vertex shader
  211. struct vertexInput {
  212.     float3 position                : POSITION;
  213.     float3 normal                : NORMAL;
  214.     float4 color                : COLOR;
  215.     float2 texCoord                : TEXCOORD0;
  216. };
  217.  
  218. // Vertex shader output, passed in to pixel shader
  219. struct vertexOutput2 {
  220.     float4 Position  : POSITION;  // in clip space
  221.     float4 color0    : COLOR0;
  222.     float4 color1    : COLOR1;
  223.     float4 TexCoord  : TEXCOORD0;
  224.     float4 btn_x : TEXCOORD1; // binormal.x, tangent.x, normal.x
  225.     float4 btn_y : TEXCOORD2; // binormal.y, tangent.y, normal.y
  226.     float4 btn_z : TEXCOORD3; // binormal.z, tangent.z, normal.z
  227.        float  fog        : FOG;
  228. };
  229.  
  230. // Vertex shader output, passed in to pixel shader
  231. struct vertexOutput3 {
  232.     float4 Position  : POSITION;  // in clip space
  233.     float2 TexCoord  : TEXCOORD0;
  234.     float3 TexCoord1 : TEXCOORD1; // first row of the 3x3 transform from tangent to cube space
  235.     float3 TexCoord2 : TEXCOORD2; // second row of the 3x3 transform from tangent to cube space
  236.     float3 TexCoord3 : TEXCOORD3; // third row of the 3x3 transform from tangent to cube space
  237.  
  238.     float2 bumpCoord0 : TEXCOORD4;
  239.     float2 bumpCoord1 : TEXCOORD5;
  240.     float2 bumpCoord2 : TEXCOORD6;
  241.     
  242.     float3 eyeVector  : TEXCOORD7;
  243.        float  fog        : FOG;
  244. };
  245.  
  246. //------------------------------------
  247.  
  248. // Vertex shader which computes waves, tangent basis to waves, bump map texture coordinates.
  249. vertexOutput2 VS_Transform2(vertexInput IN,
  250.                             uniform float time,
  251.                               uniform float waveFreq,
  252.                               uniform float waveAmp,
  253.                               uniform WAVE theWaves[NWAVES],
  254.                               uniform float4x4 theWorldViewProj,
  255.                               uniform float4x4 theView,
  256.                             uniform float2 textureScale,
  257.                             uniform float2 bumpSpeed,                                      
  258.                             uniform float BumpScale,
  259.                               uniform float3 theEyePosition,
  260.                               uniform float theFogEnd,
  261.                               uniform float theFogEndMinusStartInv
  262.                             )
  263. {
  264.     vertexOutput2 OUT;
  265.  
  266.     // We're combining two wave functions.  Hard code these values
  267.     // eventually for better performance?    
  268.     theWaves[0].freq = waveFreq;
  269.     theWaves[0].amp = waveAmp;
  270.  
  271.     theWaves[1].freq = waveFreq*2.0;
  272.     theWaves[1].amp = waveAmp*0.5;
  273.  
  274.     float3 P = IN.position;
  275.     
  276.     // Now convert world position to camera space.
  277.     // Note that we don't use World Matrix * View Matrix here, 'cause the World Matrix is the identity matrix.
  278.     float4 positionCamSpace = mul( float4(P, 1.0), theView );
  279.  
  280.     // NOTE: P is in camera space
  281.     OUT.fog = clamp(((theFogEnd - positionCamSpace.z) *  theFogEndMinusStartInv), 0.0f, 1.0f);
  282.  
  283.     // sum waves    
  284.     float ddx = 0.0, ddy = 0.0;
  285.     for(int i=0; i < NWAVES; i++) {
  286.         P.z += evaluateWave(theWaves[i], P.xy, time); //!NOTE changed this to xy from xz, due to Empire Earth code
  287.         float deriv = evaluateWaveDeriv(theWaves[i], P.xy, time);
  288.         ddx += deriv * theWaves[i].dir.x;
  289.         ddy += deriv * theWaves[i].dir.y;
  290.     }
  291.  
  292.     // Transform position to clip space
  293.     OUT.Position = mul(float4(P, 1.0), theWorldViewProj); 
  294.     
  295.     // compute tangent basis.  This is used to convert object space to texture space.
  296.     // N is the normal to the surface, T is the tangent and B is the binormal.  T & B
  297.     // follow the texture coordinate axes u and v.
  298.     float3 B = float3(1, ddx, 0) * BumpScale;
  299.     float3 T = float3(0, ddy, 1) * BumpScale;
  300.     float3 N = normalize(float3(-ddx, 1, -ddy));
  301.  
  302.     // Now we pass in (time in seconds) fmod 200.0, so we don't have to do it for each vertex
  303.  
  304.     // pass texture coordinates for fetching the normal map
  305.     OUT.TexCoord.xy = IN.texCoord*textureScale + timeMod * bumpSpeed;
  306.     OUT.TexCoord.z = 0;
  307.     OUT.TexCoord.w = 1;
  308.  
  309.     // compute the eye vector (going from shaded point to eye) in cube space
  310.     float3 theEyeVector = (theEyePosition - P).xzy; //swap z & y (in Empire Earth code, Z points up, not Y)
  311.     theEyeVector = normalize(theEyeVector);
  312.  
  313.     OUT.btn_x = float4(B.x, T.x, N.x, theEyeVector.x);
  314.     OUT.btn_y = float4(B.y, T.y, N.y, -theEyeVector.y);
  315.     OUT.btn_z = float4(B.z, T.z, N.z, theEyeVector.z);
  316.  
  317.     half facing = 1.0 - max(dot(theEyeVector, N), 0); // 1 if perpendicular to water surface, 0 if parallel
  318.     
  319.     // fresnel - could use 1D tex lookup for this
  320.     // Fresnel reflectance factor.  Water will be more reflective at when looked at long a grazing angle.
  321.     // When looking straight down at water, the surface will reflect very little.
  322.     // Setting fresnelBias to 1.0 means there will be no Fresnel effect.  A setting of 0 means
  323.     // the full effect will be used.
  324.     const float kFresnelBias = 0.5f;
  325.     half fresnel = kFresnelBias + (1.0-kFresnelBias)*pow(facing, fresnelPower);
  326.     OUT.color0 = fresnel * reflectionColor * reflectionAmount;
  327.     OUT.color0.a = 0.4;  // Alpha value of pixel
  328.     
  329.     // Interpolate between 2 water colors, depending on angle of eye to water surface
  330.     half4 waterColor = lerp(deepColor, shallowColor, facing);
  331.     OUT.color1 = waterColor;
  332.     
  333.     return OUT;
  334. }
  335.  
  336.  
  337. // Vertex shader which computes waves, tangent basis to waves, bump map texture coordinates.
  338. vertexOutput3 VS_Transform3(vertexInput IN,
  339.                             uniform float time,
  340.                               uniform float waveFreq,
  341.                               uniform float waveAmp,
  342.                               uniform WAVE theWaves[NWAVES],
  343.                               uniform float4x4 theWorldViewProj,
  344.                               uniform float4x4 theWorldMatrix,
  345.                               uniform float4x4 theView,
  346.                             uniform float2 textureScale,
  347.                             uniform float2 bumpSpeed,                                      
  348.                             uniform float BumpScale,
  349.                               uniform float3 theEyePosition,
  350.                               uniform float theFogEnd,
  351.                               uniform float theFogEndMinusStartInv
  352.                             )
  353. {
  354.     vertexOutput3 OUT;
  355.  
  356.     // We're combining two wave functions.  Hard code these values
  357.     // eventually for better performance?    
  358.     theWaves[0].freq = waveFreq;
  359.     theWaves[0].amp = waveAmp;
  360.  
  361.     theWaves[1].freq = waveFreq*2.0;
  362.     theWaves[1].amp = waveAmp*0.5;
  363.  
  364.     float3 P = IN.position;
  365.     
  366.     // Now convert world position to camera space.
  367.     // Note that we don't use World Matrix * View Matrix here, 'cause the World Matrix is the identity matrix.
  368.     float4 positionCamSpace = mul( float4(P, 1.0), theView );
  369.  
  370.     // NOTE: P is in camera space
  371.     OUT.fog = clamp(((theFogEnd - positionCamSpace.z) *  theFogEndMinusStartInv), 0.0f, 1.0f);
  372.  
  373.     // sum waves    
  374.     float ddx = 0.0, ddy = 0.0;
  375.     for(int i=0; i < NWAVES; i++) {
  376.         P.z += evaluateWave(theWaves[i], P.xy, time); //!NOTE changed this to xy from xz, due to Empire Earth code
  377.         float deriv = evaluateWaveDeriv(theWaves[i], P.xy, time);
  378. //        P.z += evaluateWaveSharp(theWaves[i], P.xy, time, 2); //!NOTE changed this to xy from xz
  379. //        float deriv = evaluateWaveDerivSharp(theWaves[i], P.xy, time, 2);
  380.         ddx += deriv * theWaves[i].dir.x;
  381.         ddy += deriv * theWaves[i].dir.y;
  382.     }
  383.  
  384.     // Transform position to clip space
  385.     OUT.Position = mul(float4(P, 1.0), theWorldViewProj); 
  386.     
  387.     // compute tangent basis.  This is used to convert object space to texture space.
  388.     // N is the normal to the surface, T is the tangent and B is the binormal.  T & B
  389.     // follow the texture coordinate axes u and v.
  390.     float3 B = float3(1, ddx, 0);
  391.     float3 T = float3(0, ddy, 1);
  392.     float3 N = float3(-ddx, 1, -ddy);
  393.  
  394.     // pass texture coordinates for fetching the normal map
  395.     OUT.TexCoord.xy = IN.texCoord*textureScale;
  396.  
  397.     // Now we pass in (time in seconds) fmod 200.0, so we don't have to do it for each vertex
  398.     //time = fmod(time, 20.0); // fmod is the floating point remainder
  399.     //OUT.bumpCoord0.xy = IN.texCoord*textureScale + time*bumpSpeed;
  400.     //OUT.bumpCoord1.xy = IN.texCoord*textureScale*2.0 + time*bumpSpeed*4.0;
  401.     //OUT.bumpCoord2.xy = IN.texCoord*textureScale*4.0 + time*bumpSpeed*8.0;
  402.     OUT.bumpCoord0.xy = IN.texCoord*textureScale + timeMod*bumpSpeed;
  403.     OUT.bumpCoord1.xy = IN.texCoord*textureScale*2.0 + timeMod*bumpSpeed*4.0;
  404.     OUT.bumpCoord2.xy = IN.texCoord*textureScale*4.0 + timeMod*bumpSpeed*8.0;
  405.  
  406.     // compute the 3x3 tranform from tangent space to object space
  407.     float3x3 objToTangentSpace;
  408.     // first rows are the tangent and binormal scaled by the bump scale
  409.     objToTangentSpace[0] = BumpScale * normalize(T);
  410.     objToTangentSpace[1] = BumpScale * normalize(B);
  411.     objToTangentSpace[2] = normalize(N);
  412.  
  413.     OUT.TexCoord1.xyz = mul(objToTangentSpace, theWorldMatrix[0].xyz);
  414.     OUT.TexCoord2.xyz = mul(objToTangentSpace, theWorldMatrix[1].xyz);
  415.     OUT.TexCoord3.xyz = mul(objToTangentSpace, theWorldMatrix[2].xyz);
  416.  
  417.     // compute the eye vector (going from shaded point to eye) in cube space
  418.     float3 theEyeVector = theEyePosition - P;
  419.     OUT.eyeVector = theEyeVector.xzy; //swap z & y (in Empire Earth code, Z points up, not Y)
  420.     return OUT;
  421. }
  422.  
  423. //-----------------------------------
  424. // Advanced pixel shader.  Uses bump map, environment map, Fresnel reflectance (reflects more
  425. // at grazing angle, reflects little if looking straight down), high dynamic range (bright areas in
  426. // env. map are "blown out"), facing (color shifts depending on whether
  427. // you're looking straight down or at a grazing angle).
  428. float4 PS_Textured3( vertexOutput3 IN,
  429.                      uniform half4 shallowColor,
  430.                      uniform half4 deepColor,
  431.                      uniform samplerCUBE EnvironmentMap,
  432.                      uniform sampler2D NormalMap,
  433.                      uniform half4 reflectionColor,
  434.                      uniform half4 reflectionAmount,
  435.                     uniform half fresnelPower,
  436.                     uniform half hdrMultiplier
  437.                     ): COLOR
  438. {
  439.     // sum normal maps
  440.     half4 t0 = tex2D(NormalMap, IN.bumpCoord0.xy)*2.0-1.0;
  441.     half4 t1 = tex2D(NormalMap, IN.bumpCoord1.xy)*2.0-1.0;
  442.     half4 t2 = tex2D(NormalMap, IN.bumpCoord2.xy)*2.0-1.0;
  443.     half3 N = t0.xyz + t1.xyz + t2.xyz;
  444.  
  445.     half3x3 m; // tangent to world matrix
  446.     m[0] = IN.TexCoord1;
  447.     m[1] = IN.TexCoord2;
  448.     m[2] = IN.TexCoord3;
  449.     half3 Nw = mul(m, N.xyz);
  450.     Nw = normalize(Nw); // normal to water surface, taking bump map & waves into account
  451.  
  452.     // Get reflection vector & look up value in environment map.
  453.     float3 E = normalize(IN.eyeVector);
  454.     half3 R = reflect(-E, Nw);
  455.     half4 reflection = texCUBE(EnvironmentMap, R);
  456.  
  457.     // hdr effect (multiplier in alpha channel)
  458.     reflection.rgb *= (1.0 + reflection.a*hdrMultiplier);
  459.  
  460.     // fresnel - could use 1D tex lookup for this
  461.     // Fresnel reflectance factor.  Water will be more reflective at when looked at long a grazing angle.
  462.     // When looking straight down at water, the surface will reflect very little.
  463.     // Setting fresnelBias to 1.0 means there will be no Fresnel effect.  A setting of 0 means
  464.     // the full effect will be used.
  465.     const float kFresnelBias = 0.1f;
  466.     half facing = 1.0 - max(dot(E, Nw), 0); // 1 if perpendicular to water surface, 0 if parallel
  467.     half fresnel = kFresnelBias + (1.0-kFresnelBias)*pow(facing, fresnelPower);
  468.  
  469.     // Interpolate between 2 water colors, depending on angle of eye to water surface
  470.     half4 waterColor = lerp(deepColor, shallowColor, facing);
  471.  
  472.     float4 color;
  473.     color = waterColor + reflection*reflectionColor*reflectionAmount*fresnel;
  474. //    color = waterColor;
  475. //    color = fresnel;
  476. //    color = reflection;
  477.     
  478.     color.a = 0.4; // Alpha value of pixel
  479.     return color;
  480. }
  481.  
  482. // A technique is the effect we're trying to achieve.
  483. //-----------------------------------
  484.  
  485. // Intermediate vertex & pixel shader.  Environment map & bump mapping.
  486. technique RenderWaterMid
  487. {
  488.     pass p0 
  489.     {        
  490.         VertexShader = compile vs_1_1 VS_Transform2(time,waveFreq, waveAmp, wave, worldViewProj,
  491.                                                     view, textureScale, bumpSpeed, bumpHeight,
  492.                                                     eyePositionW, fogEnd, fogEndMinusStartInv);
  493.         ZEnable = true; // was true
  494.         ZWriteEnable = true; // was true
  495.         CullMode = CCW; // was None; We won't see the river if we go under water (happens if cammera follows a rocking boat)
  496.         PixelShader =
  497.             asm
  498.             {
  499.                 ps_1_1
  500.  
  501.                 tex t0 
  502.                 texm3x3pad   t1,  t0_bx2   
  503.                 texm3x3pad   t2,  t0_bx2   
  504.                 texm3x3vspec t3,  t0_bx2  
  505.  
  506.                 mad            r0.rgb, t3, v0, v1;
  507.                 +mov        r0.a, v0; 
  508.             };
  509.         Sampler[0] = (normalMapSampler);
  510.         Sampler[1] = (normalMapSampler);
  511.         Sampler[2] = (normalMapSampler);
  512.         Sampler[3] = (envMapSampler);
  513.     }
  514. }
  515.  
  516. // Whole tamale.  Environment map, bump map, Fresnel reflectance factor, High Dynamic Range, water changes color
  517. // depending on eye vector & water's nomal.
  518. technique RenderWater
  519. {
  520.     pass p0 
  521.     {        
  522.         VertexShader = compile vs_2_0 VS_Transform3(time,waveFreq, waveAmp, wave,
  523.                                                     worldViewProj, worldMatrix, view,
  524.                                                     textureScale, bumpSpeed, bumpHeight,
  525.                                                     eyePositionW, fogEnd, fogEndMinusStartInv );
  526.         ZEnable = true;
  527.         ZWriteEnable = true;
  528.         CullMode = CCW; // was None; We won't see the river if we go under water (happens if cammera follows a rocking boat)
  529.         PixelShader  = compile ps_2_0 PS_Textured3(shallowColor, deepColor, envMapSampler,
  530.                                                     normalMapSampler, 
  531.                                                     reflectionColor, reflectionAmount,
  532.                                                     fresnelPower, hdrMultiplier);
  533.     }
  534. }